<?php

/**
 * 
 * @desc 框架系统异常捕捉类
 * @author keluo <pycorvn@yeah.net>
 * @since 2011-5-22 23:53:55
 */
class SCException extends Exception {
	/**
	 * 
	 * 系统错误处理
	 * @param integer $errNo 错误级别
	 * @param string $errMsg
	 * @param string $errFile
	 * @param integer $errLine
	 */
	public function errorHandler($errNo, $errMsg, $errFile, $errLine) {
		$log = array(
			'code' => $errNo,
			'file' => $errFile,
			'line' => $errLine,
			'message' => $errMsg,
			'trace' =>$this->getDebugTraceString()
		);
		
		$this->log($log); // 记录错误信息到日志
		
		$debug = SCConfig::get('DEBUG');
		switch($errNo) {
			
			// NOTICE & WARNING级别，不显示调试页
			case E_NOTICE:
			case E_USER_NOTICE:
			case E_WARNING:
			case E_USER_WARNING:
				#$debug && $this->showDebugPage($log);
			break;
			
			// 其他错误异常，显示调试页
			default:
				$this->showDebugPage($log);
				$this->halt();
			break;
		}
	}
	
	/**
	 * 异常处理
	 * @param Exception $e
	 */
	public function exceptionHandler(Exception $e) {
		$log = array(
			'code' => $e->getCode(),
			'file' => $e->getFile(),
			'line' => $e->getLine(),
			'message' => $e->getMessage(),
			'trace' =>$this->getDebugTraceString()
		);
		$this->log($log);
		$this->showDebugPage($log);
		
		$this->halt();
	}
	
	/**
	 * 显示debug页面
	 * @param array $data
	 */
	protected function showDebugPage(array $data) {
		if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 
			strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { // ajax请求
			echo '异常代码：', $this->translate($data['code']), PHP_EOL;
			echo '异常信息：', $data['message'], PHP_EOL;
			echo '触发位置：', $data['file'], '(', $data['line'],')', PHP_EOL;
			echo '堆栈跟踪：', PHP_EOL;
			echo $data['trace'];
		} else {
			echo '<meta http-equiv="content-type" content="text/html;charset=utf-8">';
			echo '<div style="font-family: 微软雅黑,Monaco,Consolas,monospace;font-size:14px;color:#CD6839;
				text-shadow:1px 1px #eee;padding:10px;clear:both;box-shadow: 0 0 8px #BBBBBB;">';
			echo '异常代码： ', $this->translate($data['code']), '<br />';
			echo '异常信息： <span style="color:red">', $data['message'], '</span><br />';
			echo '触发位置： ', $data['file'], '(', $data['line'],')<br />';
			echo '<div style="border-top:1px dashed silver;padding-top:5px;margin:5px 0;">堆栈跟踪：</div>';
			echo nl2br($data['trace']);
			echo '<div style="text-align:right;font-size:11px;">';
			echo '<a href="http://www.scabish.cn/framework">www.scabish.cn/framework</a></div>';
			echo '</div>';
		}
	}
	
	/**
	 * 记录异常信息到日志
	 * @param array $log
	 */
	protected function log(array $log) {
		if(false !== stripos($log['code'], 'is deprecated in PHP')) return;
		$log_path = rtrim(SCConfig::get('LOG_PATH'), '/');
		$log_path || $log_path = SC_APP_PATH.'/log';
		$target_path = $log_path;
		SCFunction::directoryCreate($target_path, 0777);
		
		$target_file = $log_path.'/'.date('Ym').'.log';
		if(file_exists($target_file) && is_file($target_file)) {
		} else {
			touch($target_file);
			chmod($target_file, 0777);
		}
		
		$msg = '['.date('Y-m-d H:i:s').']'.PHP_EOL;
		$msg .= '异常代码: '.$this->translate($log['code']).PHP_EOL;
		$msg .= '异常信息: '.$log['message'].PHP_EOL;
		$msg .= '发生文件: '.$log['file'].'('.$log['line'].')'.PHP_EOL;
		$msg .= '堆栈跟踪: '.PHP_EOL.$log['trace'].PHP_EOL;
		$msg .= str_pad('', 100, '-').PHP_EOL;
		
		file_put_contents($target_file, $msg.file_get_contents($target_file));
	}
	
	protected function translate($code) {
		$map = array(
			E_ERROR => 'E_ERROR',
			E_WARNING => 'E_WARNING',
			E_PARSE => 'E_PARSE',
			E_NOTICE => 'E_NOTICE',
			E_CORE_ERROR => 'E_CORE_ERROR',
			E_CORE_WARNING => 'E_CORE_WARNING',
			E_COMPILE_ERROR => 'E_COMPILE_ERROR',
			E_COMPILE_WARNING => 'E_COMPILE_WARNING',
			E_USER_ERROR => 'E_USER_ERROR',
			E_USER_WARNING => 'E_USER_WARNING',
			E_USER_NOTICE => 'E_USER_NOTICE',
			E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
			E_DEPRECATED => 'E_DEPRECATED',
			E_ALL => 'E_ALL',
		);
		return isset($map[$code]) ? $map[$code] : 'E_UNKNOWN';
	}
	/**
	 * 终止程序执行
	 */
	protected function halt() {
		die;
	}
	
	/**
	 * 获取完整debug跟踪栈
	 */
	protected function getDebugTraceString() {
		ob_start();
		debug_print_backtrace();
		$trace = ob_get_contents();
		ob_clean();
		$trace = explode("\n", $trace);
		array_shift($trace);
		return trim(implode("\n", $trace), "\n");
	}
}